package com.filldream.fastboot.core.manager;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.filldream.fastboot.base.entity.Account;
import com.filldream.fastboot.base.entity.SmsRecord;
import com.filldream.fastboot.base.entity.SmsTemplate;
import com.filldream.fastboot.base.mapper.SmsRecordMapper;
import com.filldream.fastboot.base.mapper.SmsTemplateMapper;
import com.filldream.fastboot.base.request.CheckCodeSTO;
import com.filldream.fastboot.base.request.SendCodeSTO;
import com.filldream.fastboot.common.constant.PatternEx;
import com.filldream.fastboot.common.entity.B;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.R;
import com.filldream.fastboot.common.util.entity.sms.SmsTemplateModel;
import com.filldream.fastboot.common.util.*;
import com.filldream.fastboot.core.cache.CacheMap;
import com.filldream.fastboot.core.cache.CacheObj;
import com.filldream.fastboot.core.cache.CacheUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author RickSun && iFillDream
 * @version 1.0
 * @data 2020-05-07 18:21
 * @description AccountManager
 */
@Service
public class SmsRecordManager {

    @Resource
    private SmsTemplateMapper smsTemplateMapper;

    @Resource
    private SmsRecordMapper smsRecordMapper;
    @Resource
    private AccountManager accountManager;

    /**
     * 校验验证码
     * @param checkCodeSTO
     * @return
     */
    public B checkCode(CheckCodeSTO checkCodeSTO){
        //查询
        List<SmsRecord> smsRecords = smsRecordMapper.selectList(
                new QueryWrapper<SmsRecord>()
                        .eq("cell_phone", checkCodeSTO.getCellPhone())
                        .in("status", Arrays.asList(1, 2))
                        .eq("type", checkCodeSTO.getType())
                        .eq("msg_code",checkCodeSTO.getCheckCode())
                        .orderByDesc("create_time")
        );
        if(smsRecords.isEmpty()){
            return B.fail(ErrorCode.CHECKCODE_ERR.reMsg());
        }
        SmsRecord record = smsRecords.get(0);

        //校验是否过期
        Calendar cal = Calendar.getInstance();
        cal.setTime(record.getCreateTime());
        cal.add(Calendar.MINUTE, 5);
        Date expiresTime = cal.getTime();
        if(expiresTime.getTime() < System.currentTimeMillis()){
            record.setStatus(4);
            smsRecordMapper.updateById(record);
            return B.fail("短信已过期");
        }else{
            record.setStatus(3);
            smsRecordMapper.updateById(record);
            return B.success();
        }

    }


    /**
     * 发送短信验证码
     * @param sendCodeSTO
     * @return
     */
    public B sendPhoneCode(SendCodeSTO sendCodeSTO){

        //校验手机号是否被绑定
        Integer type = sendCodeSTO.getType();
        String cellPhone = sendCodeSTO.getCellPhone();
        Assert.checkEx(PatternEx.telephone,cellPhone,"请输入正确的手机号");
        Account account = accountManager.selectByPhone(cellPhone);

        if( type.equals(0) ){//绑定/注册
            Assert.checkBoolean( account == null , ErrorCode.TELEPHONE_EXIT.reMsg());
        }else if( type.equals(1) ){//找回密码
            Assert.isEmpty( account , ErrorCode.USER_NOT_EXIST.reMsg());
        } else if( type.equals(2) ){//更换手机号
            Assert.checkBoolean( account == null , ErrorCode.USER_EXIST.reMsg());
        } else if( type.equals(4) ){//登录
            Assert.isEmpty( account , ErrorCode.USER_NOT_EXIST.reMsg());
        }else{
            return B.fail("短信发送类型错误(" + type + ")");
        }

        //校验近期是否有发送过验证码且是没用过的
        List<SmsRecord> smsRecords = querySendInTime(cellPhone, sendCodeSTO.getType());
        //即将发送的验证码
        boolean doSave = smsRecords.isEmpty();
        String code = doSave ? RandomUtil.randomNumberString(6) : smsRecords.get(0).getMsgCode();

        //发送短信
        Map<String,String> smsMap = new HashMap<>();
        smsMap.put("code",code);

        SmsTemplate byType = getByType(1);
        SmsTemplateModel smsTemplateModel = TransferUtil.changeToObj(byType, SmsTemplateModel.class);
        smsTemplateModel.setCellPhone( cellPhone );
        smsTemplateModel.setMessageMap( smsMap );
        Map<String, Object> map = SmsUtil.sendNormalMsg(smsTemplateModel);

        if((int)map.get("code") != 0){
            return R.diy(ErrorCode.BASE_ERR,"短信发送失败");
        }
        boolean sendTrue = map.get("code").toString().toUpperCase().equals("OK");
        if(doSave){
            SmsRecord smsRecord = new SmsRecord();
            smsRecord.setStatus(sendTrue ? 1 : 0);
            smsRecord.setCreateTime(new Date());
            smsRecord.setCellPhone(cellPhone);
            smsRecord.setMsgCode(code);
            smsRecord.setType(sendCodeSTO.getType());
            smsRecord.setMsgContent(code);
            smsRecord.setReturnRemark( sendTrue ? "ok" : map.get("message").toString() );
            return B.checkSuccess(smsRecordMapper.insert(smsRecord));
        }else{
            return B.success();
        }
    }

    /**
     * 获取短信模板
     * @param type
     * @return
     */
    public SmsTemplate getByType(Integer type) {
        CacheObj<SmsTemplate> cache = CacheUtil.getCache(CacheMap.MSG_TEMPLATE_DETAIL, SmsTemplate.class, type);
        SmsTemplate smsTemplateData = cache.getData();
        if(smsTemplateData != null){
            return smsTemplateData;
        }

        SmsTemplate result = smsTemplateMapper.selectOne(
                new LambdaQueryWrapper<SmsTemplate>().eq(SmsTemplate::getType,type)
        );
        Assert.isNull( result,ErrorCode.MSG_TEMPLATE_ERR.reMsg("未找到-"+type) );
        CacheUtil.cacheObj(cache.getCacheKey(),result,60);
        return result;
    }


    /**
     * @author RickSun && iFillDream
     * @Description 判断五分钟内是否发送过短信
     * @Date 2020/5/8 10:29
     * @Param [cellPhone, type]
     * @return java.util.List<SmsRecord>
     **/
    public List<SmsRecord> querySendInTime(String cellPhone,Integer type) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.MINUTE, -5);

        List<SmsRecord> smsRecords = smsRecordMapper.selectList(
                new QueryWrapper<SmsRecord>().eq("cell_phone",cellPhone)
                        .between("create_time",cal.getTime(), new Date())
                        .eq("type",type).between("status",1,2)
        );
        return smsRecords;
    }

}
